﻿using System;
using System.Data;

using zijian666.Converts.Core;

namespace zijian666.Converts.Extensions;

/// <summary>
/// <seealso cref="IDataRecord"/> 扩展方法
/// </summary>
internal static class DataRecordExtensions
{
    /// <summary>
    /// 获取 <see cref="IDataRecord"/> 中的值
    /// </summary>
    /// <typeparam name="T">值的类型</typeparam>
    /// <param name="record"></param>
    /// <param name="index">索引</param>
    /// <returns></returns>
    public static ConvertResult<T> GetValue<T>(this IDataRecord record, int index)
    {
        if (Nullable.GetUnderlyingType(typeof(T)) is not null && record.IsDBNull(index))
        {
            return new (default);
        }
        var handler = GetValueHelper<T>.Handler;
        if (handler is not null)
        {
            try
            {
                return handler(record, index);
            }
            catch
            {

            }
        }

        return ConvertResult<T>.FAIL;
    }

    /// <summary>
    /// 用于获取 <seealso cref="IDataRecord.GetValue(int)" /> 泛型委托的帮助类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    private class GetValueHelper<T>
    {
        /// <summary>
        /// <seealso cref="IDataRecord.GetValue(int)" /> 泛型委托
        /// </summary>
        public static readonly Func<IDataRecord, int, T>? Handler = CreateHandler();

        /// <summary>
        /// 创建 <seealso cref="IDataRecord.GetValue(int)" /> 泛型委托
        /// </summary>
        /// <returns></returns>
        private static Func<IDataRecord, int, T>? CreateHandler()
        {
            var type = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T);
            if (type.IsSystemType())
            {
                var name = "Get" + type.GetFriendlyName();
                var method = typeof(IDataRecord).GetMethod(name);
                if (method is not null && method.ReturnType == type && method.GetParameters().Length == 1 && method.GetParameters()[0].ParameterType == typeof(int))
                {
                    return (Func<IDataRecord, int, T>)method.CreateDelegate(typeof(Func<IDataRecord, int, T>));
                }
            }
            return null;
        }
    }
}
